msg_tool\scripts\musica/
sc.rs

1//! Musica Script (.sc)
2use crate::scripts::base::*;
3use crate::types::*;
4use crate::utils::encoding::*;
5use anyhow::Result;
6use std::io::Write;
7
8#[derive(Debug)]
9/// Musica Script Builder
10pub struct MusicaBuilder {}
11
12impl MusicaBuilder {
13    /// Create a new MusicaBuilder
14    pub fn new() -> Self {
15        MusicaBuilder {}
16    }
17}
18
19impl ScriptBuilder for MusicaBuilder {
20    fn default_encoding(&self) -> Encoding {
21        Encoding::Cp932
22    }
23
24    fn build_script(
25        &self,
26        buf: Vec<u8>,
27        _filename: &str,
28        encoding: Encoding,
29        _archive_encoding: Encoding,
30        config: &ExtraConfig,
31        _archive: Option<&Box<dyn Script>>,
32    ) -> Result<Box<dyn Script>> {
33        Ok(Box::new(MusicaScript::new(buf, encoding, config)?))
34    }
35
36    fn extensions(&self) -> &'static [&'static str] {
37        &["sc"]
38    }
39
40    fn script_type(&self) -> &'static ScriptType {
41        &ScriptType::Musica
42    }
43}
44
45#[derive(Debug)]
46pub struct MusicaScript {
47    lines: Vec<Vec<String>>,
48}
49
50impl MusicaScript {
51    pub fn new(buf: Vec<u8>, encoding: Encoding, _config: &ExtraConfig) -> Result<Self> {
52        let decoded = decode_to_string(encoding, &buf, true)?;
53        let mut lines = Vec::new();
54        for line in decoded.lines() {
55            let parts: Vec<String> = line.split(' ').map(|s| s.to_string()).collect();
56            lines.push(parts);
57        }
58        Ok(MusicaScript { lines })
59    }
60}
61
62impl Script for MusicaScript {
63    fn default_output_script_type(&self) -> OutputScriptType {
64        OutputScriptType::Json
65    }
66
67    fn default_format_type(&self) -> FormatOptions {
68        FormatOptions::None
69    }
70
71    fn extract_messages(&self) -> Result<Vec<Message>> {
72        let mut messages = Vec::new();
73        for parts in &self.lines {
74            if parts.is_empty() {
75                continue;
76            }
77            // .message <id> <voice> <name> <text>
78            if parts[0] == ".message" && parts.len() >= 5 {
79                let name_index = parts.len() - 2;
80                let text_index = parts.len() - 1;
81                let name = parts[name_index].clone();
82                let text = parts[text_index].clone();
83                let message = Message {
84                    name: if name.is_empty() { None } else { Some(name) },
85                    message: text,
86                };
87                messages.push(message);
88            }
89        }
90        Ok(messages)
91    }
92
93    fn import_messages<'a>(
94        &'a self,
95        messages: Vec<Message>,
96        file: Box<dyn WriteSeek + 'a>,
97        _filename: &str,
98        encoding: Encoding,
99        replacement: Option<&'a ReplacementTable>,
100    ) -> Result<()> {
101        let mut writer = std::io::BufWriter::new(file);
102        let mut mes = messages.iter();
103        let mut me = mes.next();
104        for parts in &self.lines {
105            let mut parts = parts.clone();
106            if parts.is_empty() {
107                writeln!(writer)?;
108                continue;
109            }
110            if parts[0] == ".message" && parts.len() >= 5 {
111                let m = match me {
112                    Some(m) => m,
113                    None => return Err(anyhow::anyhow!("Not enough messages to import.")),
114                };
115                let name_index = parts.len() - 2;
116                let text_index = parts.len() - 1;
117                if !parts[name_index].is_empty() {
118                    let mut name = match &m.name {
119                        Some(n) => n.clone(),
120                        None => {
121                            return Err(anyhow::anyhow!(
122                                "Message name is missing for message: {}",
123                                m.message
124                            ));
125                        }
126                    };
127                    if let Some(repl) = replacement {
128                        for (k, v) in &repl.map {
129                            name = name.replace(k, v);
130                        }
131                    }
132                    parts[name_index] = name.replace(' ', "\u{3000}");
133                }
134                let mut text = m.message.clone();
135                if let Some(repl) = replacement {
136                    for (k, v) in &repl.map {
137                        text = text.replace(k, v);
138                    }
139                }
140                parts[text_index] = text.replace(' ', "\u{3000}");
141                me = mes.next();
142            }
143            let line = parts.join(" ");
144            let d = encode_string(encoding, &line, false)?;
145            writer.write_all(&d)?;
146            writeln!(writer)?;
147        }
148        if me.is_some() || mes.next().is_some() {
149            return Err(anyhow::anyhow!("Too many messages to import."));
150        }
151        writer.flush()?;
152        Ok(())
153    }
154}